﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MensErgerJeNiet.Includes;
using MensErgerJeNiet.Includes.Exceptions;
using MensErgerJeNiet.Model.Vakjes;

namespace MensErgerJeNiet.Model
{
    class SpeelBord
    {
        private Vakje[] speelBord; //array ook bedoeld, straks voor de display, voor een mooie weergave
        //houd de begin vakjes van de spelers bij
        //het is de bedoeling dat de index uit de spelerlijst gekoppeld wordt aan de index van beginSpeelVakjesSpeler
        //zo heeft iedere speler 1 beginvakje (op het bord, vakje A)
        private BeginSpeelVeldVakje[] beginSpeelVakjesSpelers;

        public SpeelBord(SpelerLijst spelerLijst)
        {
            int aantalSpelers = spelerLijst.AantalSpelers();
            int aantalVakjes = aantalSpelers*10;
            speelBord = new Vakje[aantalVakjes]; //10 vakjes per speler
            beginSpeelVakjesSpelers = new BeginSpeelVeldVakje[aantalSpelers];

            int tienCounter = 0;
            //deelt de vakken in
            for (int i = 0; i < aantalVakjes; i++)
            {
                Vakje tmpSpeelVakje;
                //om de tien vakjes is er een begin vakje voor een speler
                //zorgt ervoor dat hij niet meer spelers gaat indelen, dan wat ingesteld is (i loopt zowiso tot 40, omdat het speelbord 40 vakjes is)
                //als i nou groter is dan het aantal spelers * 10, dan voegt hij geen nieuwe beginspeelvakjes meer in
                if(i%10 == 0 && (i < aantalSpelers*10))
                {
                    tmpSpeelVakje = new BeginSpeelVeldVakje();
                    tmpSpeelVakje.Type = VakjeType.BEGINSPEELVAKJE; //vakje A
                    beginSpeelVakjesSpelers[i/10] = (BeginSpeelVeldVakje)tmpSpeelVakje;
                    //kent het beginvakje (vakje A) toe aan de speler
                    //en maakt de speler eigenaar van het vakje (zie de functie: SetSpelerBeginSpeelVeldVakje)
                    spelerLijst.SetSpelerBeginSpeelVeldVakje((i/10), (BeginSpeelVeldVakje) tmpSpeelVakje);

                } else //anders een normaal speelvakje
                {
                    tmpSpeelVakje = new SpeelVakje();
                    tmpSpeelVakje.Type = VakjeType.SPEELVAKJE;
                
                    
                }
                
                tmpSpeelVakje.ID = i;
                speelBord[i] = tmpSpeelVakje;

                if(i > 0)
                {
                    speelBord[i - 1].Next = tmpSpeelVakje; //linkt het volgende vakje door
                }
            }


            //sluit de uiteindes aan elkaar, zodat het een cirkel wordt
            // in spel wordt gecheckt of een speler een rondje gemaakt heeft
            speelBord[aantalVakjes - 1].Next = speelBord[0];
        }

        //LET OP! als aantalVakjes groter dan een 6 is en je staat in de eindfase,
        //dan krijg je een nullpointer reference exception (dit gebeurt toch niet omdat je nooit in de eindfase kan gooien)
        //het gebeurt omdat er dan geen Previous meer is (a van de eindvakjes heeft geen previous en een vakje ook niet)
        /// <summary>
        /// verplaatst een pion een x aantal stappen (inclusief het einde heen en terug) en checkt of er geslagen moet worden.
        /// Als de zet niet mogenlijk is, dan gooit hij een GeenZetMogelijkException op.
        /// </summary>
        /// <param name="pion"></param>
        /// <param name="aantalVakjes"></param>
        /// <param name="spelers"></param>
        public void movePionCurrentSpeler(Pion pion, int aantalVakjes, SpelerLijst spelers)
        {
            Vakje vakjePionToPlaceIn = pion.StaatInVakje;
            Vakje oudeVakjePion = pion.StaatInVakje;
            Speler currentSpeler = spelers.CurrentSpeler;

            if (vakjePionToPlaceIn != null)
            {
                bool loopBackEindVakjes = false;
                bool isInEindFase = false;
                //loopt steeds naar het volgende vakje, aan de hand van het aantal gegooide ogen
                for (int i = 0; i < aantalVakjes; i++)
                {
                    //als het ID van het volgende vakje, gelijk is aan het beginvakje van de pion
                    //dan staat de pion dus op het laatste vakje van het rondje
                    //Console.WriteLine("vakje to place in is null: "+ (vakjePionToPlaceIn == null));
                    if (vakjePionToPlaceIn.Next != null && (vakjePionToPlaceIn.Next.ID == currentSpeler.beginSpeelVeldVakje.ID))
                    {
                           //het volgende vakje is het eindvakje van de huidige speler
                            vakjePionToPlaceIn = currentSpeler.eindVakjes[0];
                            isInEindFase = true; //zit nou in de eind fase met de pion
                        
                    }
                    else
                    {
                        if (isInEindFase)
                        {
                            EindVakje eindvakje = (EindVakje)vakjePionToPlaceIn;

                            if (vakjePionToPlaceIn.Next == null) //CHECK of ie al aan het einde is van de eindvakjes van de speler
                                loopBackEindVakjes = true; //dan gaat ie terug lopen

                            if (loopBackEindVakjes)
                            {
                                vakjePionToPlaceIn = eindvakje.Previous; //als ie aan het eind geweest is, moet ie terug lopen
                            }
                            else
                            {
                                vakjePionToPlaceIn = eindvakje.Next;
                            }


                        }
                        else
                        { //normale afhandeling in het speel veld, als de pion nog niet bij de finish is
                            vakjePionToPlaceIn = vakjePionToPlaceIn.Next;
                        }
                    }
                }

                //als het vakje in de eindfase niet leeg is, dan is de zet niet mogenlijk
                if (vakjePionToPlaceIn.SpelerPion != null && isInEindFase)
                    throw new GeenZetMogelijkException("zet is niet mogenlijk");
                else if (vakjePionToPlaceIn.SpelerPion != null) //als het vakje, waar de pion moet komen niet leeg is, dan slaat hij de pion die daar staat
                    slaPion(vakjePionToPlaceIn.SpelerPion);

                oudeVakjePion.SpelerPion = null; //het vakje waar de pion eerst stond, wordt nou leeg
                vakjePionToPlaceIn.SpelerPion = pion; //het vakje waar de pion moet komen, krijgt de pion - EIGENLIJK DUBBEL V
                pion.StaatInVakje = vakjePionToPlaceIn; //in de pion wordt opgeslagen in welk vakje hij staat, om straks weer te nexten - EIGENLIJK DUBBEL ^

            }
            else
            {
                Console.WriteLine("pion staat nergens!!!");
                throw new Exception("pion staat nergens, bij het verzetten van de pion!");
            }
        }

        /// <summary>
        /// Zet een pion in een vakje, aan de hand van een array index nummer van de vakjes
        /// </summary>
        /// <param name="pion">Pion die in een vakje gezet moet worden</param>
        /// <param name="vakNr">Het nummer van het vakje waar de pion op het speelbord moet komen!</param>
        public void setPionInVakjeOpSpeelbord(Pion pion, int vakNr)
        {
            if (speelBord[vakNr].SpelerPion != null)
                slaPion(speelBord[vakNr].SpelerPion);

            speelBord[vakNr].SpelerPion = pion;
            pion.StaatInVakje = speelBord[vakNr];
        }

        /// <summary>
        /// Zet een pion in een vakje, aan de hand van een array index nummer van de vakjes
        /// </summary>
        /// <param name="pion">Pion die in een vakje gezet moet worden</param>
        /// <param name="vakNr">Het nummer van het vakje waar de pion op het speelbord moet komen!</param>
        public void setPionInVakjeOpSpeelbord(Pion pion, Vakje vakje)
        {
            if (vakje.SpelerPion != null)
                slaPion(vakje.SpelerPion);

            vakje.SpelerPion = pion;
            pion.StaatInVakje = vakje;
        }

        public void setPionOpBegiVakjeSpeelBord(Pion pion, Speler speler)
        {
            BeginSpeelVeldVakje spelerBeginSpeelVeldVakje = speler.beginSpeelVeldVakje;
            setPionInVakjeOpSpeelbord(pion, spelerBeginSpeelVeldVakje);
        }

        /// <summary>
        /// Zet de pion in een van de beginvakjes van de eigenaar van de pion.
        /// Hier wordt de eigenaar gezocht aan de hand van een spelerlijst.
        /// </summary>
        /// <param name="pion"></param>
        /// <param name="spelerLijst"></param>
        public void setPionInBeginVakjeVanEigenaar(Pion pion, SpelerLijst spelerLijst)
        {
            Speler eigenaar = null;
            foreach (Speler speler in spelerLijst.Spelers)
            {
                foreach (Pion pionSpeler in speler.PionnenLijst)
                {
                    if (pionSpeler.Equals(pion))
                        eigenaar = speler;
                }
            }

            setPionInBeginVakjeVanEigenaar(pion, eigenaar);
        }

        public void setPionInBeginVakjeVanEigenaar(Pion pion, Speler eigenaar)
        {
            if (eigenaar != null)
            {
                BeginVakje beginVakje = new BeginVakje();
                foreach (BeginVakje vakje in eigenaar.beginVakjes)
                {
                    if (vakje == null)
                        beginVakje = vakje;
                }

                if (beginVakje.SpelerPion != null) //als het beginvakje bezet is door een andere pion (kan ook je eigen pion zijn)
                    slaPion(beginVakje.SpelerPion); //slaat hem
                beginVakje.SpelerPion = pion; //stelt in het vakje in, welke pion er in staat
                Vakje vakjeWaarPionInStond = pion.StaatInVakje; //haalt het vakje op, waar de pion in stond (ergens  in B dus)

                if (vakjeWaarPionInStond != null)
                    vakjeWaarPionInStond.SpelerPion = null; //zet het vakje op null

                pion.StaatInVakje = beginVakje; //stelt in de pion in, waar hij nu staat
            }
        }

        /// <summary>
        /// Slaat de pion. Dit houd in dat het vakje waar de pion nu staat leeg wordt en de pion verplaatst wordt
        /// naar een leeg beginveld van de eigenaar van de pion.
        /// </summary>
        /// <param name="geslagenPion"></param>
        public void slaPion(Pion geslagenPion)
        {
            Speler spelerVanPion = geslagenPion.BegonnenInVakje.VanSpeler;
            if(spelerVanPion != null)
            {
                Vakje vakjeWaarPionNuStaat = geslagenPion.StaatInVakje;
                geslagenPion.StaatInVakje = null;
                vakjeWaarPionNuStaat.SpelerPion = null;
                setPionInBeginVakjeVanEigenaar(geslagenPion, spelerVanPion);
            }
        }

        /// <summary>
        /// Zet alle pionnen van een speler in de beginpositie
        /// </summary>
        /// <param name="Eigenaar"></param>
        public void setAllePionenInBeginVakjesEigenaar(Speler Eigenaar)
        {
            for (int i = 0; i < Eigenaar.beginVakjes.Length; i++)
            {
                Eigenaar.beginVakjes[i].SpelerPion = Eigenaar.PionnenLijst[i];
                Eigenaar.PionnenLijst[i].StaatInVakje = Eigenaar.beginVakjes[i];
                Eigenaar.PionnenLijst[i].BegonnenInVakje = Eigenaar.beginVakjes[i];
            }
        }

        

        /// <summary>
        /// geeft het volledige speelbord als string terug
        /// </summary>
        /// <returns></returns>
        public string BordToString()
        {
            string totStr = "SpeelBord:\n";
            for (int i = 0; i < speelBord.Length; i++)
            {
                string bevatPion = "";
                string spelerNaam = "";
                bevatPion = (speelBord[i].SpelerPion == null) ? "False " : speelBord[i].SpelerPion.ID +" ";

                if(speelBord[i].Type ==VakjeType.BEGINSPEELVAKJE)
                {
                    BeginSpeelVeldVakje beginVakje = (BeginSpeelVeldVakje)speelBord[i];
                    spelerNaam = ", eigenaar: " + beginVakje.VanSpeler.Naam;
                }
                totStr += "vakje: " + speelBord[i].ID + " - " + speelBord[i].Type + ", bevat pion: " + bevatPion + spelerNaam + "\n";
            }
            return totStr + "\n\n";
        }

        /// <summary>
        /// geeft een vakje terug aan de hand van een index nummer
        /// </summary>
        /// <param name="index"></param>
        /// <returns></returns>
        public Vakje GetVakje(int index)
        {
            if(index > -1 && index < speelBord.Length)
                return speelBord[index];

            return null;
        }
    }
}
